home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Packmags
/
NewsFlash - Issue 07 (1990-01)(UGA - 17-Bit Software)(Disk 1 of 2)[a].zip
/
NewsFlash - Issue 07 (1990-01)(UGA - 17-Bit Software)(Disk 1 of 2)[a].adf
/
prog
/
tp.doc
< prev
Wrap
Text File
|
1988-01-19
|
20KB
|
462 lines
The TP (TyPe) project for UGA newsletter. First Chapter.
Author: Jeroen K Sparla
In 3 issues for the UGA newsletter, we will create 3 programs,
one written in the language C, and two written in assembly, for
displaying documentation files.
With this three programs you're able to display doc files in a
no-nonsence fast and efficient way.
Our goal is to create a utility that converts a ascii-docfile into
an executable program, in order to display itself.
We are gonna do this job in three stages:
1) A C-program, intended for the amiga-users who do have a certain knowledge
of the program language C, but are curious how to program the
amiga specific things like screens etc.
This version of TP is rather straightforward and does nothing special,
if it's a matter in fact, it's quite unusable; but it should show
in a step by step way how to setup things for the amiga.
This program is kept short which resulted in a not too nice Amy program.
If there is any interest i'll rewrite it in a nice Intuition context,
every bit of code performing a legal job in the intuiton context.
Routines suchs as the LeftMouseButton() are bad in this multitasking
environment, and will probably not work with new amiga releases.
On the other hand, rewritting this program with a full, nice Intuition
interface will result in a executable about twice as big as this one.
If you're interested in such an application, fully explained, please
let me know and i'll write one.
For the C language refer to books suchs as K&R.(or Ammeraal from academic
service if you're Dutch).
2) A 68000 machinecode program performing the same as the C version above.
Intended for the machinecode freaks amongst you.
3) The final machinecode version which attaches itself to the docfile turning
it in a executable which displays itself.
Tricky code will be used for this one with lots of commandline options.
There are a few disadventages in this oproach:
- You can't edit/print/display-in-an-other-way the docfile
to suit your needs because it's part of an executable.
An unpack option should cover the problem.
- The same executable extends each individual doc file, i do not
think this approach is faster/better than a standalone TP in the
C directory or in RAM:-disk
The advantage for a magazine like this is that the executable docfile
can be crunched; the standalone versions of TP can be crunched ofcourse
but the ascii-file as an argument can't !
So the executable method CAN mean winning diskspace IF you crunch.
A step by step explanation by the C program (included on this disk, tp.c)
will follow:
--------------------------------------------------------------------------------
#define GTX 560 /* Emulated Gadget coordinates topleft & bottomright */
#define GTY 0
#define GBX 579
#define GBY 9
In the construction '#define xxx yyy'
xxx will be replaced by yyy during compilation.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
extern struct Screen *OpenScreen(); /* prototyping for Aztec */
We will tell the compiler that the OpenScreen() function will return
a pointer to a screen structure and not to an ordinary integer.
The extern tells the compiler that the function OpenScreen() is not part
of my program but in the extern functionlibrary.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
LONG IntuitionBase=0L; /* pointer to intuition.library */
LONG GfxBase=0L; /* pointer to graphics.library */
This pointers to libraries are initialised to NULL, so the cleanup routine
will know what libraries to close. If they are still NULLpointers
the libraries will not be closed.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
/* our own screen definitions */
struct NewScreen ns= { 0,0, /* top x,y */
640,200,1, /* lower x,y and number of bitplanes */
0,1, /* detail and block pen */
HIRES, /* we want a hires screen */
CUSTOMSCREEN, /* not the workbench but our own */
NULL, /* default font */
/* the title */
(UBYTE *)"TP(L) V0.9 (c)1989 by Trihedral Systems -=[YEP]=-",
NULL /* always null, no screengadgets */
};
If we want to open a screen, there are two structures involved in it,
the NewScreen structure and the Screen structure.
The NewScreen structure is a subset of the full Screen structure, only
including the values that must be present to open a screen.
A pointer to this structure will be passed to OpenScreen().
OpenScreen returns a pointer to the full Screen structure which contains
information such as your mouse position on that screen.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
struct RastPort *rp=NULL; /* pointer to rasterport */
A pointer to the rasterport. Later pointed to the rasterport from the screen.
The rasterport contains information where to find the bitmap(s).
(in our example just one).
This pointer must be passed to every function which want to do something
in/with this bitmaps.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
struct Screen *screen=NULL; /* pointer to screen */
A pointer to the Screen structure. Initialised by the OpenScreen() function.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
FILE *infile=NULL; /* pointer to our ascii textfile */
Standard C for getting a filepointer to our text input file.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
int error=0; /* errornumber during init */
int new=FALSE; /* user want to start again ? */
int scndscr=FALSE; /* are we past the first screen ? */
int BottomLine; /* lowest scanline we want to reach */
We will use a few global variables to inform the program about:
error : holds the errornumber when it encounters an error.
new : if TRUE, the user wants to start at the beginning of the file.
scndscr: if TRUE, the user has left the first screen.
BottomLine: contains the number of the last scanline+offset we want to use.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
void Init()
{ /* try to open the graphics library */
GfxBase=OpenLibrary("graphics.library",0);
if(GfxBase==NULL)
{ puts("Can't open graphics.library");
error=10;
}
/* try to open the intuition library */
IntuitionBase=OpenLibrary("intuition.library",0);
if(IntuitionBase==NULL)
{ puts("Can't open intuition.library");
error=20;
}
Opening libraries is a quite standard procedure on the Amiga.
By opening a library you gain access to standard Amiga functions
for performing things like opening screens etc.
We need the graphics library for the Text() and Move() calls for instance.
OpenLibrary() returns the base adress for the jumptable, if it returns
NULL the library couldn't be opened.
/* try to open the new screen */
screen=OpenScreen(&ns);
if(screen==NULL)
{ puts("Can't open screen");
error=30;
}
This piece of code will open the requested screen. If it succeeds it will
return a pointer to the Screen structure. If screen is still NULL, the screen
has failed to open. (too many screens open, no memory for bitmaps....)
/* place screen in front (should be done automaticly.. just in case */
ScreenToFront(screen);
With this routine we ask intuiton to place our screen in front of all the
others. Normally, if a screen is opened it's automaticly placed in front
of the others.
/* initialise pointer to the rasterport from the screen */
rp = &screen->RastPort;
We want to know where to find the rasterport from the screen to pass it
along with the functions who want to know where the bitmaps are.
/* set the drawing pen to the second color (0,1,2...) of the palette */
SetAPen(rp,1);
Since we have only one bitplane asked, we can only choose colors 0 and 1
for the Drawingpen. In our case 0 is the background color and 1 the
cursorcolor.
}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
int LeftMouseButton()
{ APTR address=0xbfe000; /* CIAA, bit 6, 1:released, 0:pressed */
/* this should be address 0xbfe001, but */
/* we work on word (2byte) boundaries */
The left mousebutton is connected to CIA-A pin 6. The CIA is located in
the memorymap at address 0xbfe001, but since we read words (2 bytes) we
refer to memorylocation 0xbfe000.
I must tell you that this is NOT the way to read the mousebutton in a
multitasking/multiwindow/multieverything environment, but since there is
no IDCMPport (IntuitionDirectCommunicationsMessagePort) available in this
program, intuiton can't tell me in a nice way that either mousebutton has
been pressed.
unsigned short Mouse;
Mouse=(unsigned short)(*address); /* fetch data CIAA */
Here we read the state of the button.
if((Mouse & 64)==64) /* bit 6 set ? */
return(FALSE); /* yes, button not pressed */
else
return(TRUE); /* no, button is pressed */
}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
void DrawGadget()
{ SetAPen(rp,0); /* set drawpen to backgroundcolor */
Specify the fill color.
RectFill(rp,GTX,GTY,GBX,GBY); /* draw filled box */
And fill our 'gadget', it's located in the screentitle.
SetAPen(rp,1); /* set drawpen to cursorcolor */
Specify the drawcolor
Move(rp,GTX+4,GTY+2); /* move to topleftedge */
Draw(rp,GBX-4,GTY+2); /* draw interior box */
Draw(rp,GBX-4,GBY-2);
Draw(rp,GTX+4,GBY-2);
Draw(rp,GTX+4,GTY+2);
And draw a box.
This routine does nothing more than drawing a box within a filled box
if the screentitlebar. It's just a drawing, not a gadget such as intuition
supports. In the routine NextScreen() we wait till the user moved the pointer
in this area and then skip to the next screen.
If i should use a intuition gadget, the code would increase and this is
doing the job as well.
}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
CLS()
{ SetAPen(rp,0); /* background color */
/* fill until scanline 200 if NTSC, in PAL until line 256 */
RectFill(rp,0,10,639,BottomLine==201 ? 199 : 255);
Here is checked if we are clearing a NTSC or a PAL screen.
SetAPen(rp,1); /* back to cursor color */
DrawGadget(); /* place the gadget, just in case... */
And the 'gadget' image is redrawn, just in case it messed up.
Clearing the screen by a RectFill() with the background color is quite fast.
}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
NextScreen()
{ int x,y,hit=FALSE; /* mouse x,y position and mouseleftbutton */
new=FALSE; /* does the user want to restart */
while((!hit) && (!new)) /* user didn't take any action */
You should recognize this flags.
{ hit=LeftMouseButton(); /* left mousebutton ? */
x=screen->MouseX; /* fetch mouse coordinates */
y=screen->MouseY;
Here we refer to the Screen structure. We want to know where the mouse-
pointer is located.
/* if the pointer is in our gadget and we are at least at the secondscreen */
if(x>GTX && x<GBX && y>GTY && y<GBY && scndscr)
new=TRUE; /* the user wants to restart */
If the mouse is in our 'gadget' area, the user request us to go to the
beginning of the textfile.
If this is the first screen displayed, going to the beginning makes no sence
and it provides repeating itself.
}
CLS(); /* always clear the screen */
if(hit && new) /* user in gadget and mousebutton pressed */
error=(90); /* user wants to quit */
If the user was in the gadgetarea and hit the left mousebutton, he
requests the main program to cleanup things and quit by specifying
error number 90. (this could really be any number...)
if(hit) /* mousebutton pressed ? */
scndscr=TRUE; /* this means we are reading the next screen */
If the user pressed the left mousebutton, we leave the first screen.
}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
CleanUp()
{
if(infile) fclose(infile); /* close the textfile */
if(screen) CloseScreen(screen); /* give screen back.. */
if(IntuitionBase) CloseLibrary(IntuitionBase); /* don't need this libs anymore */
if(GfxBase) CloseLibrary(GfxBase);
We have to clean up the mess we made. (your mother doesn't work here...)
Since we initialised the pointers to NULL, they won't be closed if
the opening didn't succeed.
}
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
_abort()
{ puts("-=INTERRUPTED=- user abort request");
/* user wants to quit by pressing [ctrl]C on keyboard */
CleanUp(); /* cleanup the system before */
exit(100); /* exit with errornumber */
}
This routine is called if the 'c' key with the controlkey is pressed.
It substitutes the library routine abort(), therefore it's preceded with an _
This routine probably won't work with other compilers than Aztec.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
main(argc,argv)
int argc; /* urgument count (1..n) */
char *argv[]; /* the values (0..n-1) */
We pass one command line parameter, the asciifilename.
argc contains the number of parameters including the name of the program.
argv[0] points to the name of the executed program.
argv[1] points to the first parameter passed,ie the asciifilename.
we will use argv[0] to check if the program was called TP or TPL,
if the programname is TP, we execute the NTSC version, if the name
is TPL, we execute the PAL version. So renameing the program influences
it's behaviour.
{ int xpos,ypos,len; /* current x,y cursor position & length */
char str[81]; /* from the string stored int str */
Contains the string read in from the file.
Since we read a line at a time + \0, we don't need any more storage.
char ch; /* dummy character */
if(argc!=2) /* more or less than 1 argument ? */
{ puts("USAGE : TP(L) <ascii-file>"); /* display help */
Check the number of arguments passed
CleanUp(); /* cleanup and exit with error */
error=40;
goto Quit;
}
infile=fopen(argv[1],"r"); /* try to open the specified file */
Open the requested file in read mode
if(infile==NULL) /* nop, not found... */
{ puts("Can't open specified file");
Dos couldn't open/locate the file, cleanup and quit.
CleanUp();
error=50;
goto Quit;
}
/* this is kinda tricky:
since we have NTSC (200 scanlines) and PAL (256 scanlines) version Amy's
the name of the command defines the version you want to use.
if you name the program :
TP you are requesting the NTSC version.
TPL you are requesting the PAL version.
*/
BottomLine=201; /* standard NTSC */
if(toupper(argv[0][2])=='L') /* if command's 3th character is an L */
{ BottomLine=257; /* we want the large screen */
ns.Height=256; /* redefine screen height */
}
This code does the NTSC/PAL trick.
The NewScreen Height will be set to PAL if the 3th character from the
programname is an 'L' or an 'l'.
The Bottomline will be set accordingly to 200 or 256 plus the 1 offset
for the starting ypos=17 location. We increase the scanlinenumber by 8,
and with the odd 17 starting position, we want the testvalue of the bottemline
to be odd either.
Init(); /* initialise the system */
if(error) /* error returned ? */
goto Quit;
If an error occured, go cleanup and quit.
CLS(); /* clear the screen */
xpos=0; ypos=17; /* cursor position */
Move(rp,xpos,ypos); /* go set the cursor */
Go to the starting cursor position
while((ch=getc(infile)) != EOF) /* read one char ahead to detect EOF */
{ ungetc(ch,infile); /* put character back in buffer */
fgets(str,81,infile); /* get a string of maximal 80+\0 chars */
len=strlen(str); /* calculate it's length */
if(len==80) /* buffer was full without reading a \0 */
len++;
Move(rp,xpos,ypos); /* move to cursor position */
Text(rp,str,--len); /* output the textline */
ypos+=8; /* 'linefeed' */
if(ypos==BottomLine) /* did we reach the bootom */
{ NextScreen(); /* yes, do the next screen */
ypos=17; /* cursor back to top */
if(error==90) /* did user want to quit ? */
{ CleanUp(); /* cleanup and quit */
goto Quit;
}
if(new) /* user wants to restart */
{ new=FALSE; /* reset flags */
scndscr=FALSE;
if(fseek(infile,0L,0L)) /* goto start of file */
puts("Something wrong with seek"); /* how could this happen ? */
}
}
}
The code above should explain itself now i think.
NextScreen(); /* clear the last screen */
CleanUp(); /* cleanup the theatre */
Quit:
exit(error);
Back to caller (Dos shell i suppose) returning the errornumber
}
--------------------------------------------------------------------------------
In the next issue i'll discuss the machinelanguage version of this program.
The approach will be different.
We won't open an intuition screen but a view, and we won't use dos to read
the ascii file, but use the trackdisk.device which enables quik
backreading in the file, so a real up and down browser will be included.
If you have any questions, here's my address:
Jeroen K Sparla
Ganzediepstraat 34
7523 PH Enschede
The Netherlands